/*
//the nodeType can be PCB, MsgEnv, or other objects
template <class nodeType>
class Queue{
		private:
				 nodeType * head;
				 nodeType * tail;
				 int size;

		public:
				 Queue(){head=tail=NULL;size=0;};
				 Queue(int NumOfNode);
				 ~Queue();
				 void enqueue(nodeType * newNode);
				 nodeType * dequeue();
				 int getsize();//count number of nodes in the queue
				 int empty();
};
*/
#include "global.h"

class Stack{
		private:
				 int size;
				 int top;
				 char * data;
		public:
				 Stack(int size);//malloc space for data
				 ~Stack();
				 int * pop();
				 void push(int * item);
};

class MsgEnv{
		public:
				 int sender_pid;
				 int target_pid;
				 int num_clock_ticks;
				 char type; //use number to represent the type of message
				 MsgEnv * next; //link to the next message envelope
				 char msg_data[Max_Env_Data];
				 MsgEnv(){
				 			 sender_pid=target_pid=num_clock_ticks=0;
							 type=0;
							 next=0;
							 msg_data[Max_Env_Data]=0;
	  		    };
};

class MsgEnvQ{
        private:
                MsgEnv * head;
                MsgEnv * tail;
                int size;
        public:
        MsgEnvQ(){head=tail=0;size=0;};
        MsgEnvQ(int NumOfNode);
        ~MsgEnvQ(){delete [] head, tail, size;};
        void enqueue(MsgEnv * newMsgEnv);
        MsgEnv * dequeue();
        int getsize();//count number of nodes in the queue
};


//process control block
class PCB{
		public:
				 int pid; //process ID
				 int priority;
				 int status;
				 //Stack * stack; //stack pointer
				 void * address;//pointer point to the process function
				 //jmp_buf procContext;//jump buffer for setjmp, longjmp
				 MsgEnvQ * msgQ; //local message envelope queue
				 PCB * next; //link to other PCB
};


class PCBQ{
        private:
                PCB * head;
                PCB * tail;
                int size;
        public:
        PCBQ(){head=tail=0;size=0;};
        //PCBQ(int NumOfNode);
        ~PCBQ(){delete [] head, tail, size;};
        void enqueue(PCB * newPCB);
        PCB * dequeue();
        int getsize();//count number of nodes in the queue
};

/*
why is blocked_on_receive queue redundant??
and still need to add 4 priority levels for the blocked_on_resource queue 
class BlockedQ{
		private:
				 Queue<PCB> pcbQ[Num_BlockedTypes];//PCB queues
				 PCB * tail;
				 PCB * head;
		public:
				 BlockedQ();
				 ~BlockedQ();
				 //return total number of blocked PCBs
				 int getSize();
				 //return total number of PCBs in the selected type queue
				 int getSize(int priority);
				 void enqueue(PCB * newpcb, int blockedType);
				 PCB * dequeue(int blockedtype);
				 int empty();
};
class ReadyQ{
private:
Queue<PCB> pcbQ[Num_PriorityLevels];//PCB queues
PCB * head;
PCB * tail;
public:
ReadyQ();
~ReadyQ();
//return total number of PCBs in the ready queue
int getSize();
//return total number of PCBs in the selected priority
ready queue
int getSize(int priority);
void enqueue(PCB * newpcb, int priority);
PCB * dequeue();//dequeue and return the PCB with the
*/
struct TraceBuffer{
		 int target_id;
		 int sender_id;
		 int msg_type;
		 int time_stamp;
};


struct initTable {
int pid;
int priority;
int status;
int stack_size;
void * start_address;
};
//Kernal Class
class RTX{
		private:
				  //current process pointer
				  PCB * cur_proc;			  		
				  
  				  PCB * PCB_list[Num_Proc];
				  
				  int system_time;
				  MsgEnvQ * free_env_Q;
	//not for partial			  ReadyQ * ready_queue; //with 4 priority queues
	//not for partial			  BlockedQ * blocked_queue; //with 2 priority queues
				  TraceBuffer * send_trace_buffer[TraceBufferSize];
				  TraceBuffer * receive_trace_buffer[TraceBufferSize];
		public:
				 RTX();
				 //initialization function which sets up variables,
				 //queues, pointers, objects and initialize processes
				 void initialization(initTable init_table[]);
				 
				 //go through the ready queue and blocked queue to find the
				 //PCB with the target pid and return the pointer pointing
				 //to the PCB
				 PCB * search_PCB(int target_pid);
				 
				 void addTrace(MsgEnv*);
				 void process_switch();
				 void context_switch(PCB * next);
				 
				 void rpq_enqueue(PCB*);
				 PCB* rpq_dequeue();
				 
				 
				 //user API for real-time kernel
				 int send_message( int dest_process_id, MsgEnv *msg_envelope );
				 MsgEnv * receive_message( );
				 MsgEnv * request_msg_env( );
				 int release_msg_env ( MsgEnv * memory_block );
				 int release_processor( );
				 int request_process_status( MsgEnv * memory_block );
				 int terminate( );
				 int change_priority(int new_priority, int target_process_id);
	//not for partial			 int request_delay( int time_delay, int wakeup_code, MsgEnv *message_envelope );
				 int send_console_chars(MsgEnv * message_envelope );
				 int get_console_chars(MsgEnv * message_envelope );
				 int get_trace_buffers( MsgEnv * message_envelope);
};
